package com.unboundedprime.osgisurveillance.monitor.ioc;

import java.beans.XMLDecoder;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * A thin wrapper around the Java beans container loader.
 */
public class ZeptoIocContainer {
	
	private Map<Class, Object> objects = new HashMap<Class, Object>();
	
	public ZeptoIocContainer(final String classPathContextPath) throws AmbiguousInterfaceException {
		this(ZeptoIocContainer.class.getResourceAsStream(classPathContextPath));
	}
	
	public ZeptoIocContainer(final InputStream inputStream) throws AmbiguousInterfaceException {
		this.digestObjects(inputStream);
	}
	
	private void digestObjects(final InputStream inputStream) throws AmbiguousInterfaceException {
		final XMLDecoder xmlDecoder = new XMLDecoder(inputStream, this);
		
		Object object = xmlDecoder.readObject();
		
		while (object != null) {
			catalogObject(object);
			
			try {
				object = xmlDecoder.readObject();
			} catch (ArrayIndexOutOfBoundsException ex) {
				object = null;
			}
		}
		
		xmlDecoder.close();
	}
	
	private void catalogObject(final Object object) throws AmbiguousInterfaceException {
		final Class objectClass = object.getClass();
		final Class[] interfaces = objectClass.getInterfaces();
		
		for (final Class interfaceClass : interfaces) {
			
			if (this.objects.containsKey(interfaceClass)) {
				final Object existingObject = this.objects.get(interfaceClass);
				
				throw new AmbiguousInterfaceException("Error mapping class '"+objectClass.getName()+"' to interface. Interfaces '"+interfaceClass.getName()+"' is already mapped to class '"+existingObject.getClass().getName()+"'.");
			}
			
			this.objects.put(interfaceClass, object);
		}
	}
	
	public <T> T getObject(final Class<T> clazz) {
		T objectInstance = null;
		
		final Object object = this.objects.get(clazz);
		
		if (object != null) {
			objectInstance = (T) object;
		}
		
		return objectInstance;
	}
	
	public static class AmbiguousInterfaceException extends Exception {

		public AmbiguousInterfaceException() {
			super();
		}

		public AmbiguousInterfaceException(Throwable throwable) {
			super(throwable);
		}

		public AmbiguousInterfaceException(String message, Throwable throwable) {
			super(message, throwable);
		}

		public AmbiguousInterfaceException(String message) {
			super(message);
		}
	}
}
